﻿using log4net;
using System;
using System.Collections.Generic;
using System.Data;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Web;

namespace System
{
    public class FileHelper
    {
        #region 目录查找

        /// <summary>
        /// 检测指定目录中是否存在指定的文件
        /// </summary>
        /// <param name="directoryPath">指定目录的绝对路径</param>
        /// <param name="searchPattern">模式字符串，"*"代表0或N个字符，"?"代表1个字符。
        /// 范例："Log*.xml"表示搜索所有以Log开头的Xml文件。</param> 
        /// <param name="isSearchChild">是否搜索子目录</param>
        public static bool Contains(string directoryPath, string searchPattern, bool isSearchChild)
        {
            try
            {
                //获取指定的文件列表
                string[] fileNames = GetFileNames(directoryPath, searchPattern, isSearchChild);

                //判断指定文件是否存在
                if (fileNames.Length == 0)
                {
                    return false;
                }
                else
                {
                    return true;
                }
            }
            catch (Exception ex)
            {
                throw new Exception(ex.Message);
                //LogHelper.WriteTraceLog(TraceLogLevel.Error, ex.Message);
            }
        }

        /// <summary>
        /// 获取指定目录及子目录中所有文件列表
        /// </summary>
        /// <param name="directoryPath">指定目录的绝对路径</param>
        /// <param name="searchPattern">模式字符串，"*"代表0或N个字符，"?"代表1个字符。
        /// 范例："Log*.xml"表示搜索所有以Log开头的Xml文件。</param>
        /// <param name="isSearchChild">是否搜索子目录</param>
        public static string[] GetFileNames(string directoryPath, string searchPattern, bool isSearchChild)
        {
            //如果目录不存在，则抛出异常
            if (!Directory.Exists(directoryPath))
            {
                throw new FileNotFoundException();
            }

            try
            {
                if (isSearchChild)
                {
                    return Directory.GetFiles(directoryPath, searchPattern, SearchOption.AllDirectories);
                }
                else
                {
                    return Directory.GetFiles(directoryPath, searchPattern, SearchOption.TopDirectoryOnly);
                }
            }
            catch (IOException ex)
            {
                throw ex;
            }
        }
        #endregion

        #region 目录操作

        /// <summary>
        /// 创建目录
        /// </summary>
        /// <param name="dir">要创建的目录路径包括目录名</param>
        public static void CreateDir(string dir)
        {
            if (dir.IsNullOrWhiteSpace()) return;
            if (!Directory.Exists(dir))
                Directory.CreateDirectory(dir);
        }

        /// <summary>
        /// 复制文件夹及包含的文件
        /// </summary>
        /// <param name="sourceDirName">原始路径</param>
        /// <param name="targetDirName">目标路径</param>
        /// <returns>true：复制成功；false：复制失败</returns>
        private static async Task<bool> CopyDir(string sourceDirName, string targetDirName, CancellationToken token)
        {
            try
            {
                if (token.IsCancellationRequested)
                    return false;
                if (sourceDirName.Substring(sourceDirName.Length - 1) != "\\")
                {
                    sourceDirName += "\\";
                }
                if (targetDirName.Substring(targetDirName.Length - 1) != "\\")
                {
                    targetDirName += "\\";
                }

                if (Directory.Exists(sourceDirName))
                {
                    if (!Directory.Exists(targetDirName))
                    {
                        Directory.CreateDirectory(targetDirName);
                    }
                    foreach (string item in Directory.GetFiles(sourceDirName))
                    {
                        File.Copy(item, targetDirName + Path.GetFileName(item), true);
                    }
                    foreach (string item in Directory.GetDirectories(sourceDirName))
                    {
                        var sourceDir = item;
                        var targetDir = $"{targetDirName}{item.Substring(item.LastIndexOf("\\") + 1)}";
                        await CopyDir(sourceDir, targetDir, token);
                    }
                }
                return true;
            }
            catch
            {
                return false;
            }
        }

        /// <summary>
        /// 复制文件夹及包含的文件
        /// </summary>
        /// <param name="sourceDirName">原始路径</param>
        /// <param name="targetDirName">目标路径</param>
        /// <returns>true：复制成功；false：复制失败</returns>
        public static CancellationTokenSource CopyDir(string sourceDirName, string targetDirName, Action<Task<bool>> action = null)
        {
            CancellationTokenSource cts = new CancellationTokenSource();
            AsyncActionHelper.RunTask(async () => await CopyDir(sourceDirName, targetDirName, cts.Token)
            .ContinueWith((a) => action?.Invoke(a)));
            return cts;
        }
        #endregion

        #region 文件操作
        /// <summary>
        /// 检测指定文件是否存在,如果存在则返回true。
        /// </summary>
        /// <param name="filePath">文件的绝对路径</param>
        public static bool IsExistFile(string filePath)
        {
            return File.Exists(filePath);
        }

        /// <summary>
        /// 获取指定文件内容
        /// 注：这里适用于读取文本类型文件
        /// </summary>
        public static List<string> GetFileContent(string fileName)
        {
            List<string> result = new List<string>();
            if (!File.Exists(fileName))
                return result;
            FileStream fs = new FileStream(fileName, FileMode.Open, FileAccess.Read, FileShare.ReadWrite);
            StreamReader reader = new StreamReader(fs);
            string line;
            while ((line = reader.ReadLine()) != null)
            {
                result.Add(line);
            }
            reader.Close();
            fs.Close();
            return result;
        }

        /// <summary>
        /// 读取JSON文件
        /// </summary>
        /// <param name="filePath">路径</param>
        /// <returns>JSON文件中的value值</returns>
        public static string GetFileContentToStr(string fileName)
        {
            string result = string.Empty;
            if (!File.Exists(fileName))
                return result;
            FileStream fs = new FileStream(fileName, FileMode.Open, FileAccess.Read, FileShare.ReadWrite);
            StreamReader reader = new StreamReader(fs);
            result = reader.ReadToEnd();
            reader.Close();
            fs.Close();
            return result;
        }

        /// <summary>
        /// 复制文件
        /// </summary>
        /// <param name="dir1">要复制的文件的路径已经全名(包括后缀)</param>
        /// <param name="dir2">目标位置,并指定新的文件名</param>
        public static void CopyFile(string dir1, string dir2)
        {
            dir1 = dir1.Replace("/", "\\");
            dir2 = dir2.Replace("/", "\\");
            if (File.Exists(dir1))
            {
                File.Copy(dir1, dir2, true);
            }
        }

        /// <summary>
        /// 将文件移动到指定目录
        /// </summary>
        /// <param name="sourceFilePath">需要移动的源文件的绝对路径</param>
        /// <param name="descDirectoryPath">移动到的目录的绝对路径</param>
        public static void Move(string sourceFilePath, string descDirectoryPath)
        {
            //获取源文件的名称
            string sourceFileName = Path.GetFileName(sourceFilePath);

            if (Directory.Exists(descDirectoryPath))
            {
                //如果目标中存在同名文件,则删除
                DeleteFile(Path.Combine(descDirectoryPath, sourceFileName));
                //将文件移动到指定目录
                File.Move(sourceFilePath, descDirectoryPath + "\\" + sourceFileName);
            }
        }

        /// <summary>
        /// 删除文件
        /// </summary>
        /// <param name="file">要删除的文件路径和名称</param>
        public static void DeleteFile(string file)
        {
            if (File.Exists(file))
            {
                File.Delete(file);
            }
        }

        /// <summary>
        /// 创建一个文件。
        /// </summary>
        /// <param name="filePath">文件的绝对路径</param>
        public static void CreateFile(string filePath)
        {
            try
            {
                //如果文件不存在则创建该文件
                if (!IsExistFile(filePath))
                {
                    //创建一个FileInfo对象
                    FileInfo file = new FileInfo(filePath);

                    //创建文件
                    FileStream fs = file.Create();

                    //关闭文件流
                    fs.Close();
                }
            }
            catch (Exception ex)
            {
                //LogHelper.WriteTraceLog(TraceLogLevel.Error, ex.Message);
                throw ex;
            }
        }

        /// <summary>
        /// 创建一个文件,并将字节流写入文件。
        /// </summary>
        /// <param name="filePath">文件的绝对路径</param>
        /// <param name="buffer">二进制流数据</param>
        public static void CreateFile(string filePath, byte[] buffer)
        {
            try
            {
                //如果文件不存在则创建该文件
                if (!IsExistFile(filePath))
                {
                    //创建一个FileInfo对象
                    FileInfo file = new FileInfo(filePath);

                    //创建文件
                    FileStream fs = file.Create();

                    //写入二进制流
                    fs.Write(buffer, 0, buffer.Length);

                    //关闭文件流
                    fs.Close();
                }
            }
            catch (Exception ex)
            {
                //LogHelper.WriteTraceLog(TraceLogLevel.Error, ex.Message);
                throw ex;
            }
        }

        /// <summary>
        /// 创建文件
        /// </summary>
        /// <param name="path">文件全路径</param>
        /// <param name="content">写入内容</param>
        public static void CreateFile(string fileName, List<string> content = null)
        {
            if (!File.Exists(fileName))
            {
                FileStream fs = new FileStream(fileName, FileMode.Create, FileAccess.Write);
                if (content != null && content.Count > 0)
                {
                    StreamWriter sw = new StreamWriter(fs);
                    foreach (string line in content)
                    {
                        sw.WriteLine(line);
                    }
                    sw.Close();
                }
                fs.Close();
            }
        }

        /// <summary>
        /// 向文本文件中写入内容
        /// </summary>
        /// <param name="filePath">文件的绝对路径</param>
        /// <param name="text">写入的内容</param>
        /// <param name="encoding">编码</param>
        public static void WriteText(string filePath, string text, Encoding encoding)
        {
            //向文件写入内容
            File.WriteAllText(filePath, text, encoding);
        }

        /// <summary>
        /// 向文本文件的尾部追加内容
        /// </summary>
        /// <param name="filePath">文件的绝对路径</param>
        /// <param name="content">写入的内容</param>
        public static void AppendText(string filePath, string content)
        {
            File.AppendAllText(filePath, content);
        }

        /// <summary>
        /// 清空文件内容
        /// </summary>
        /// <param name="filePath">文件的绝对路径</param>
        public static void ClearFile(string filePath)
        {
            //删除文件
            File.Delete(filePath);

            //重新创建该文件
            CreateFile(filePath);
        }
        #endregion

        #region 获取文件信息
        /// <summary>
        /// 获取文本文件的行数
        /// </summary>
        /// <param name="filePath">文件的绝对路径</param>        
        public static int GetLineCount(string filePath)
        {
            //将文本文件的各行读到一个字符串数组中
            string[] rows = File.ReadAllLines(filePath);

            //返回行数
            return rows.Length;
        }

        /// <summary>
        /// 获取一个文件的长度,单位为Byte
        /// </summary>
        /// <param name="filePath">文件的绝对路径</param>        
        public static long GetFileSize(string filePath)
        {
            //创建一个文件对象
            FileInfo fi = new FileInfo(filePath);

            //获取文件的大小
            return fi.Length;
        }

        /// <summary>
        /// 打印指定文件的详细信息
        /// </summary>
        /// <param name="path">指定文件的路径</param>
        public static string GetFileVersion(string path)
        {
            var tempFileVersion = string.Empty;
            if (IsExistFile(path))
            {
                FileVersionInfo info = FileVersionInfo.GetVersionInfo(path);
                tempFileVersion = info.FileVersion;
                //Console.WriteLine("文件名称=" + info.FileName);
                //Console.WriteLine("产品名称=" + info.ProductName);
                //Console.WriteLine("公司名称=" + info.CompanyName);
                //Console.WriteLine("文件版本=" + info.FileVersion);
                //Console.WriteLine("产品版本=" + info.ProductVersion);
                //// 通常版本号显示为「主版本号.次版本号.生成号.专用部件号」
                //Console.WriteLine("系统显示文件版本：" + info.ProductMajorPart + '.' + info.ProductMinorPart + '.' + info.ProductBuildPart + '.' + info.ProductPrivatePart);
                //Console.WriteLine("文件说明=" + info.FileDescription);
                //Console.WriteLine("文件语言=" + info.Language);
                //Console.WriteLine("原始文件名称=" + info.OriginalFilename);
                //Console.WriteLine("文件版权=" + info.LegalCopyright);
            }
            return tempFileVersion;
        }

        /// <summary>
        /// 计算文件大小函数(保留两位小数),Size为字节大小
        /// </summary>
        /// <param name="size">初始文件大小</param>
        /// <returns></returns>
        public static string ToFileSize(long size)
        {
            string m_strSize = "";
            long FactSize = size;
            if (FactSize < 1024.00)
                m_strSize = FactSize.ToString("F2") + " B";
            else if (FactSize >= 1024.00 && FactSize < 1048576)
                m_strSize = (FactSize / 1024.00).ToString("F2") + " KB";
            else if (FactSize >= 1048576 && FactSize < 1073741824)
                m_strSize = (FactSize / 1024.00 / 1024.00).ToString("F2") + " MB";
            else if (FactSize >= 1073741824)
                m_strSize = (FactSize / 1024.00 / 1024.00 / 1024.00).ToString("F2") + " GB";
            return m_strSize;
        }
        #endregion
    }
}